package com.dwin.h5.app.utils.http;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSource;
import okio.Buffer;

/**
 * h5混合app，通用网络请求框架，添加platform平台字段。
 */
public class OkHttpUtils {

    private static OkHttpUtils okHttpUtils;
    private static OkHttpClient okHttpClient;
    private static Handler mHandler;
    // 平台：1:android，2:ios.3:小程序,4:微信，5：后台，6：H5
    private static final String PLATFORM = "1";
    private static final String J_PUSH_ID = "jpush-registration-id"; // 极光推送id


    //  构造初始化
    private OkHttpUtils() {
        // 构建OkHttpClient
        okHttpClient = new OkHttpClient.Builder()
                // 请求的超时时间, 设置响应的超时时间,设置连接的超时时间
                .readTimeout(15000, TimeUnit.MILLISECONDS)
                .writeTimeout(15000, TimeUnit.MILLISECONDS)
                .connectTimeout(15000, TimeUnit.MILLISECONDS)
                .addInterceptor(new LoggingInterceptor())
                .addNetworkInterceptor(new LoggingInterceptor())
                .build();
        mHandler = new Handler(Looper.getMainLooper()); // 获取主线程的handler
    }

    private final Charset UTF8 = Charset.forName("UTF-8");
    class LoggingInterceptor implements Interceptor {
        private static final String TAG = "LoggingInterceptor";
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            //1.请求前--打印请求信息
            long startTime = System.nanoTime();
//            Log.e(TAG, String.format("Sending request %s on %s - %n - %s",
//                    request.url(), request.body(), request.headers(), chain.connection()));
            RequestBody requestBody = request.body();
            String body = null;        if (requestBody != null) {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                Charset charset = UTF8;
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                }
                body = buffer.readString(charset);
            }
            Log.d(TAG, "发送请求: method：" + request.method()
                    + "\nurl：" + request.url()
                    + "\n请求头：" + request.headers()
                    + "\n请求参数: " + body);

            //2.网络请求
            Response response = chain.proceed(request);
            //3.网络响应后--打印响应信息
            long endTime = System.nanoTime();
            Log.e(TAG, String.format("Received response for %s in %.1fms%n%s",
                    response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
            printResponseMessage(response);
            return response;
        }
    }

    private void printResponseMessage(Response response) {
        if (response == null || !response.isSuccessful()) {
            return;
        }
        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();
        BufferedSource source = responseBody.source();
        try {
            source.request(Long.MAX_VALUE); // Buffer the entire body.
        } catch (IOException e) {
            e.printStackTrace();
        }
        Buffer buffer = source.buffer();
        Charset charset = UTF8;
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(UTF8);
        }
        if (contentLength != 0) {
            String result = buffer.clone().readString(charset);
            Log.i("LoggingInterceptor", "Response: " + result);
        }
    }

    /**
     * 通过单例模式构造对象
     *
     * @return
     */
    public static OkHttpUtils getInstance() {
        if (okHttpUtils == null) {
            synchronized (OkHttpUtils.class) {
                if (okHttpUtils == null) {
                    okHttpUtils = new OkHttpUtils();
                }
            }
        }
        return okHttpUtils;
    }

    /**
     * 构造Get请求，封装对用的Request请求，实现方法
     *
     * @param url          访问路径
     * @param realCallback 接口回调
     */
    private void getRequest(String auth, String language, String url, final RealCallback realCallback) {
        Request request = new Request.Builder()
                .addHeader("auth", auth)
                .addHeader("language", language)
                .addHeader("platform", PLATFORM)
                .url(url)
                .get()
                .build();
        deliveryResult(realCallback, okHttpClient.newCall(request));
    }

    /**
     * 构造post 请求，封装对用的Request请求，实现方法
     *
     * @param url          请求的url
     * @param requestBody  请求参数
     * @param realCallback 结果回调的方法
     */
    private void postRequest(String auth, String language, String url, RequestBody requestBody, final RealCallback realCallback) {
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("auth", auth)
                .addHeader("language", language)
                .addHeader("platform", PLATFORM)
                .build();
        deliveryResult(realCallback, okHttpClient.newCall(request));
    }

    /**
     * 带JPush注册id的post请求
     * @param auth
     * @param language
     * @param url
     * @param requestBody
     * @param realCallback
     */
    private void postRequestV2(String auth, String language, String url, String jPushId,
                               RequestBody requestBody, final RealCallback realCallback) {
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("auth", auth)
                .addHeader("language", language)
                .addHeader("platform", PLATFORM)
                .addHeader(J_PUSH_ID, jPushId)
                .build();
        deliveryResult(realCallback, okHttpClient.newCall(request));
    }

    private void postRequestFile(String auth, String language, String url,
                                 MultipartBody filePart, final RealCallback realCallback) {
        Request request = new Request.Builder()
                .url(url)
                .post(filePart)
                .addHeader("auth", auth)
                .addHeader("language", language)
                .addHeader("platform", PLATFORM)
                .build();
        deliveryResult(realCallback, okHttpClient.newCall(request));
    }

    /**
     * 处理请求结果的回调：主线程切换
     *
     * @param realCallback
     * @param call
     */
    private void deliveryResult(final RealCallback realCallback, Call call) {
        call.enqueue(new Callback() {
            @Override
            public void onFailure(final Call call, final IOException e) {
                sendFailureThread(call, e, realCallback);
            }

            @Override
            public void onResponse(final Call call, final Response response) throws IOException {
                sendSuccessThread(call, response, realCallback);
            }
        });
    }

    /**
     * 发送成功的回调
     *
     * @param call
     * @param response
     * @param realCallback
     */
    private void sendSuccessThread(final Call call, final Response response, final RealCallback realCallback) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                realCallback.onResponse(call, response);
            }
        });
    }

    /**
     * 发送失败的回调
     *
     * @param call
     * @param e
     * @param realCallback
     */
    private void sendFailureThread(final Call call, final IOException e, final RealCallback realCallback) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                realCallback.onFailure(call, e);
            }
        });
    }

    //-----------对外公共访问的get/post方法-----------

    /**
     * get请求
     *
     * @param auth         请求头auth
     * @param baseUrl      请求url
     * @param realCallback 请求回调
     */
    public void get(String auth, String language, String baseUrl, Map<String, String> map, final RealCallback realCallback) {
        String url = getUrl(baseUrl, map);
        getRequest(auth,language, url, realCallback);
    }

    /**
     * post请求
     *
     * @param auth         请求头auth
     * @param url          请求url
     * @param realCallback 请求回调
     * @param requestBody  请求参数
     */
    public void post(String auth, String language, String url, RequestBody requestBody, final RealCallback realCallback) {
        postRequest(auth, language, url, requestBody, realCallback);
    }

    public void postV2(String auth, String language, String url,String pushId, RequestBody requestBody, final RealCallback realCallback) {
        postRequestV2(auth, language, url, pushId, requestBody, realCallback);
    }

    public void postFile(String auth, String language, String url, MultipartBody filePart, final RealCallback realCallback) {
        postRequestFile(auth, language, url,  filePart, realCallback);
    }



    // 组装http的Get请求，
    private String getUrl(String baseUrl, Map<String, String> params) {
        String url = baseUrl;
        // 添加url参数
        if (params != null) {
            Iterator<String> it = params.keySet().iterator();
            StringBuffer sb = null;
            while (it.hasNext()) {
                String key = it.next();
                String value = params.get(key);
                if (sb == null) {
                    sb = new StringBuffer();
                    sb.append("?");
                } else {
                    sb.append("&");
                }
                sb.append(key);
                sb.append("=");
                sb.append(value);
            }
            if (sb != null) {
                url += sb.toString();
            }
        }
        return url;
    }

    /**
     * http请求回调类,回调方法在UI线程中执行
     */
    public static abstract class RealCallback {
        /**
         * 请求成功回调
         *
         * @param response
         */
        public abstract void onResponse(Call call, Response response);

        /**
         * 请求失败回调
         *
         * @param e
         */
        public abstract void onFailure(Call call, IOException e);
    }
}

